<?php
if (!class_exists('Product', false)) {
    /**
     * 产品数据处理
     *
     * @author Akon(番茄红了) <aultoale@gmail.com>
     */
    class Product
    {
        /**
         * 根据分类路径删除产品数据
         *
         * @param  string  $catpath
         */
        public static function delete($catpath = null)
        {
            if (is_null($catpath)) {
                DB::delete('products');
            } elseif (preg_match('/^(\d+;)+$/', $catpath)) {
                $sql = (string) DB::select()
                    ->from('item_cats', 'cid')
                    ->where('cat_path LIKE ?', "$catpath%");
                DB::delete('products', DB::quoteInto('cid IN (?)', DB::expr($sql)));
            }
        }

        /**
         * 获取所有最底层的分类数据
         *
         * @return array
         */
        public static function lowestCats()
        {
            return DB::select()
                ->from('item_cats', array('cid', 'name'))
                ->where('is_parent=0')
                //->where('cid>=1512')
                //->order(DB::expr('RAND()'))
                ->order('cid ASC')
                ->fetchAll();
        }

        /**
         * 获取远程数据错误信息
         *
         * @param  array  $data
         * @return string
         */
        public static function remoteException($data, $func = null, $suffix = null)
        {
            if (isset($data['error_response'])) {

                $error = $data['error_response'];

                $msg = isset($error['sub_msg']) ? $error['sub_msg'] : (isset($error['msg']) ? $error['msg'] : '未知错误');
                $code = isset($error['code']) ? $error['code'] : 0;

                throw new Api_Exception($msg, $code, $func, $suffix);
            }
        }

        /**
         * 获取远程产品数量统计
         *
         * @param  int  $cid
         * @return int
         * @throws Exception
         */
        public static function remoteTotal($cid)
        {
            $api = new Taoapi();
            $api->method = 'taobao.products.search';
            $api->fields = 'product_id';
            $api->page_no = 1;
            $api->page_size = 1;
            $api->cid = $cid;

            $errorSuffix = "分类ID：{$cid}";

            for ($i = 1; $i <= 10; $i++) {
                $data = $api->send('get','json')->getArrayData();
                try {
                    self::remoteException($data, __FUNCTION__, $errorSuffix);
                    if (isset($data['products_search_response']['total_results'])) {
                        return $data['products_search_response']['total_results'];
                    }
                    CLI::output('.');
                    throw new Api_Exception("第 $i 次获取产品数量统计失败", 0, __FUNCTION__, $errorSuffix);
                } catch (Api_Exception $e) {
                    $e->code() && CLI::output('!');
                    sleep(10); // 休息10 秒钟
                }
            }
        }

        /**
         * 获取远程产品数据列表
         *
         * @param  int  $cid
         * @param  int  $page_no
         * @param  int  $page_size
         * @return array
         * @throws Exception
         */
        public static function remoteList($cid, $page_no, $page_size)
        {
            $api = new Taoapi();
            $api->method = 'taobao.products.search';
            $api->fields = 'product_id';
            $api->page_no = $page_no;
            $api->page_size = $page_size;
            $api->cid = $cid;

            $errorSuffix = "分类ID：{$cid}，页码：{$page_no}，每页记录数：{$page_size}";

            for ($i = 1; $i <= 10; $i++) {
                $data = $api->send('get','json')->getArrayData();
                try {
                    self::remoteException($data, __FUNCTION__, $errorSuffix);
                    if (isset($data['products_search_response']['products']['product'])) {
                        return $data['products_search_response']['products']['product'];
                    }
                    CLI::output('.');
                    throw new Api_Exception("第 $i 次获取产品数据列表失败", 0, __FUNCTION__, $errorSuffix);
                } catch (Api_Exception $e) {
                    $e->code() && CLI::output('!');
                    sleep(10); // 休息10 秒钟
                }
            }
        }

        /**
         * 获取远程产品数据
         *
         * @param  int  $product_id
         * @return array
         * @throws Exception
         */
        public static function remoteData($product_id)
        {
            $api = new Taoapi();
            $api->method = 'taobao.product.get';
            $api->fields = 'product_id,outer_id,cid,cat_name,props,props_str,'.
                           'name,binds,binds_str,sale_props,sale_props_str,desc,'.
                           'pic_url,pic_path,price,tsc,shop_price,standard_price,'.
                           'sale_num,rate_num,level,collect_num,status,modified,'.
                           'created,vertical_market,customer_props,property_alias,'.
                           'product_imgs,product_prop_imgs';
            $api->product_id = $product_id;

            $errorSuffix = "产品ID：{$product_id}";

            for ($i = 1; $i <= 10; $i++) {
                $data = $api->send('get','json')->getArrayData();
                try {
                    self::remoteException($data, __FUNCTION__, $errorSuffix);
                    if (isset($data['product_get_response']['product'])) {
                        return $data['product_get_response']['product'];
                    }
                    CLI::output('.');
                    throw new Api_Exception("第 $i 次获取产品数据失败", 0, __FUNCTION__, $errorSuffix);
                } catch (Api_Exception $e) {
                    $e->code() && CLI::output('!');
                    sleep(10); // 休息10 秒钟
                }
            }
        }

        /**
         * 判断分类下载是否锁定
         *
         * @param  int  $cid
         * @return bool
         */
        public static function locked($cid)
        {
            return is_file(TMPPATH."/logs/lock/products/$cid.lock");
        }

        /**
         * 锁定分类下载
         *
         * @param  int  $cid
         * @param  int  $total
         */
        public static function lock($cid, $total = 0)
        {
            $file = TMPPATH."/logs/lock/products/$cid.lock";
            file_put_contents($file, $total);
        }

    }
}

/**
 * 下载产品数据
 *
 * @author Akon(番茄红了) <aultoale@gmail.com>
 */
$productsMenu = <<<EOF

---------------------------

 1、清除产品数据

 2、下载所有产品数据

 0、返回

---------------------------

请选择 (0,1,2)：
EOF;

do {
    // 显示菜单
    $input = CLI::input($productsMenu);

    // 删除产品数据
    if ($input == 1) {

        $input = CLI::input("\n请输入产品类目ID，输入“0”将删除所有产品（多个类目请使用逗号分隔）：");

        if ($input === '0') {
            $input = CLI::input("\n确认要删除所有产品数据吗？(y,n)：");
            if (strtolower($input) == 'y')  {
                Product::delete();
                CLI::output("\n信息：所有产品数据已删除 √\n");
            }
        } elseif (preg_match('/^\d+,?$/', $input)) {
            $cids = explode(',', $input);
            foreach ($cids as $cid) {
                $cat = DB::select()
                    ->from('item_cats')
                    ->where('cid=?', $cid)
                    ->fetchRow();
                if ($cat) {
                    Product::delete($cat['cat_path']);
                    CLI::output("\n信息：类目 ({$cat['name']}) 下的所有产品已删除 √\n");
                    unset($subcats);
                } else {
                    CLI::output("\n错误：ID为 “{$cid}” 的类目不存在 ×\n");
                }
                unset($cat);
            }
            unset($cids);
        }

    // 下载所有产品数据
    } elseif ($input == 2) {

        CLI::output("\n正在获取类目信息...");

        $cats = Product::lowestCats();
        CLI::output("(共 ".count($cats)." 个产品类目)");

        $index = 0;
        foreach ($cats as $cat) {

            $index++;

            CLI::output("\n\n类目：{$cat['name']} ({$cat['cid']})，完成：".round($index/count($cats)*100, 1)."%");

            // 已锁定，跳过
            if (Product::locked($cat['cid'])) {
                CLI::output(" √");
                continue;
            }

            try {
                // 获取产品总数
                $total = (int) Product::remoteTotal($cat['cid']);
                CLI::output(" (共 ".$total." 个产品)");

                // 下载完成计数
                $down_count = 0;

                if ($total > 0 && $total) {
                    for ($i = 1; $i <= ceil($total / 10); $i++) {
                        // 获取产品列表
                        $products = (array) Product::remoteList($cat['cid'], $i, 10);

                        $i == 1 && CLI::output("\n");

                        foreach ($products as $p) {
                            // 查询产品库是否已下载
                            $found = DB::select()
                                ->from('products')
                                ->where('product_id=?', $p['product_id'])
                                ->fetchRow();
                            if ($found) {
                                $down_count++;
                                continue;
                            }

                            // 是否完成下载
                            $completed = false;

                            // 通过api远程下载
                            $data = Product::remoteData($p['product_id']);
                            if (isset($data['pic_url'])) {
                                $data['pic_url'] = preg_replace('/http:\/\/img0[0-9]\.taobaocdn.com\/bao\/uploaded\//i', '', $data['pic_url']);
                            }
                            isset($data['price'])   && $data['market_price'] = $data['price'];
                            isset($data['name'])    && $data['product_name'] = $data['name'];
                            isset($data['tsc'])     && $data['product_sn']   = $data['tsc'];
                            isset($data['desc'])    && $data['product_desc'] = $data['desc'];

                            // 只下载已确认的产品
                            if ($data['status'] != 3) {
                                $down_count++;
                                continue;
                            }

                            // 保存产品图片
                            if (isset($data['product_imgs']['product_img'])) {
                                $imgdata = $data['product_imgs']['product_img'];
                                if (!empty($imgdata)) {
                                    DB::replace('product_imgs', $imgdata);
                                }
                                unset($imgdata);
                            }

                            // 保存产品属性图片
                            if (isset($data['product_prop_imgs']['product_prop_img'])) {
                                $imgdata = $data['product_prop_imgs']['product_prop_img'];
                                if (!empty($imgdata)) {
                                    DB::replace('product_prop_imgs', $imgdata);
                                }
                                unset($imgdata);
                            }

                            unset($data['price'], $data['name'], $data['tsc'], $data['desc'], $data['product_imgs'], $data['product_prop_imgs']);

                            // 写入数据库
                            if (is_array($data)) {
                                DB::replace('products', $data);
                                $completed = true;
                                $down_count++;
                            }
                            unset($data);

                            // 写入错误日志
                            if ($completed !== true) {
                                try {
                                    CLI::output("*");
                                    throw new Api_Exception("产品数据下载失败：{$p['product_id']}", 0, null, "所属分类：{$cat['name']} ({$cat['cid']})");
                                } catch (Exception $e) {}
                            }
                            unset($found, $completed, $j);
                        }

                        CLI::output(">");
                        unset($products);
                    }
                    unset($i);
                }

                // 全部下载完成，锁定
                if ($down_count >= $total) {
                    Product::lock($cat['cid'], $total);
                    CLI::output(" √");
                }

                unset($total, $down_count);

            } catch (Exception $e) {
                CLI::output("\n\n错误：".$e->getMessage()." ×\n");
            }
            unset($cat);
        }

        CLI::output("\n所有类目产品数据下载完成 √\n");
        unset($cats);

    // 返回
    } else {
        break;
    }

    CLI::input("\n请按下回车键继续！");

} while (true);

unset($productsMenu);